<?php

define("BLUEPRINT_PARSE_DIR", dirname(__FILE__));
require(BLUEPRINT_PARSE_DIR . '/HTMLDOM.php');
require(BLUEPRINT_PARSE_DIR . '/HTMLParser.php');
require(BLUEPRINT_PARSE_DIR . '/HTMLElement.php');
require(BLUEPRINT_PARSE_DIR . '/HTMLTextNode.php');
require(BLUEPRINT_PARSE_DIR . '/PHPNode.php');
require(BLUEPRINT_PARSE_DIR . '/PHPTextNode.php');

class HTMLDocument extends HTMLDOM {
	
	var $all = array();
	var $allNodes = array();
	var $docType;
	var $htmlDecl;
	var $ignoreWhite = true;
	var $phpClasses = array();
	var $nodeType = DOM_DOCUMENT_NODE;
	
	
	function HTMLDocument($file = null) {
		if(isset($file) && file_exists($file)) {
			$this->file = $file;
			$this->parse(file_get_contents($file));
		}
	}
	
	function createElement($nodeName) {
		return new HTMLElement($nodeName, $this);
	}
	
	function createTextNode($text) {
		return new HTMLTextNode($text, $this);
	}
	
	function createPHPNode($code) {
		return new PHPNode($code, $this);
	}
	
	function createPHPTextNode($code) {
		return new PHPTextNode($code, $this);
	}
	
	function toString() {
		$string = '';
		
		if (isset($this->docType)) {
			$string .= "<!DOCTYPE " . $this->docType . ">";
		}
		
		foreach ($this->childNodes as $node) {
			if ($this->noWhite || $node->nodeStyle == 'inline') {
				$string .= $node->toString();
			} else {
				$string .= "\n" . $node->toString();
			}
		}
		
		return $string;
	}
	
	
	function parse($str) {
		$parser = new HTMLParser($str);
		unset($str);
		$this->stack = array($this);
		
		while ($parser->parse()) {
			switch ($parser->nodeType) {
				
				case HTMLParser_ELEMENT_NODE:
					$this->startElement($parser, $parser->nodeName, $parser->nodeAttributes);
				break;
				
				case HTMLParser_ENDELEMENT_NODE:
					$this->endElement($parser, $parser->nodeName);
				break;
				
				case HTMLParser_TEXT_NODE:
					$this->characterData($parser, $parser->nodeValue);
				break;
				
				case HTMLParser_COMMENT_NODE:
				break;
				
				case HTMLParser_DOCUMENT_TYPE_NODE:
					$this->docType = $parser->nodeValue;
				break;
				
				case HTMLParser_PROCESSING_INSTRUCTION_NODE:
					$this->PIHandler($parser, $parser->nodeValue);
				break;
				
			}
		}
		unset($this->stack);
	}
	
	// private functions
	// *** PARSING HANDLERS ***
	
	function getParent() {
		return $this->stack[sizeof($this->stack) - 1];
	}
	
	function startElement($parser, $name, $attrs) {
		$element = $this->createElement($name);
		$element->attributes = $attrs or $element->attributes = array();
		$element->code = $parser->nodeCode;
		if (isset($element->attributes["id"])) $this->all[$element->attributes["id"]] = $element;
		$this->allNodes[] = $element;
		$element->parentNode = $this->getParent();
		$element->startLine = $parser->currentLine;
		$this->stack[] = $element;
	}
	
	function endElement($parser, $name) {
		$element = $this->stack[count($this->stack) - 1];
		array_pop($this->stack);
		$element->updateChildRelations();
		if ($element->nodeName != $name) {
			trigger_error("End tag <strong>&lt;/$name&gt;</strong> out of place on line
				<strong>$parser->currentLine</strong> in template <strong>$this->file</strong>.<br />
				 Previous <strong>&lt;$element->nodeName&gt;</strong> element from line 
				 <strong>$element->startLine</strong> was never closed.<br />", E_USER_ERROR);
		}
		$element->endLine = $parser->currentLine;
		$element->parentNode->childNodes[] = $element;
	}
	
	function characterData($parser, $data) {
		$dataTmp = trim($data);
		if (empty($dataTmp)) {
			$data = ' ';
		} else {
			$dataTmp = ltrim($data);
			if (strlen($dataTmp) != strlen($data)) {
				$data = " $dataTmp";
			}
			$dataTmp = rtrim($data);
			if (strlen($dataTmp) != strlen($data)) {
				$data = "$dataTmp ";
			}
		}
		
		$parent = $this->getParent();
		if (isset($parent->lastChild) && $parent->lastChild->nodeType == DOM_TEXT_NODE) {
			$parent->lastChild->data = $parent->lastChild->data == ' ' ? $data : $parent->lastChild->data . $data;
		} else {
			$parent->childNodes[] = new HTMLTextNode($data, $this);
		}
	}
	
	function PIHandler($parser, $data) {
		$phpNode = $this->createPHPNode($data);
		$phpNode->parentNode = $this->getParent();
		$phpNode->parentNode->childNodes[] = $phpNode;
	}
	
}

?>